package com.meeting.meetingroom_api.service.impl;

import com.meeting.meetingroom_api.constants.ErrorMessages;
import com.meeting.meetingroom_api.dto.*;
import com.meeting.meetingroom_api.entity.*;
import com.meeting.meetingroom_api.enums.*;
import com.meeting.meetingroom_api.repository.*;
import com.meeting.meetingroom_api.service.BookingService;
import com.meeting.meetingroom_api.service.CancellationService;
import com.meeting.meetingroom_api.service.PaymentService; // For potential refund processing
import jakarta.persistence.EntityNotFoundException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;

@Service
public class CancellationServiceImpl implements CancellationService {

    private final CancellationRepository cancellationRepository;
    private final BookingRepository bookingRepository;
    private final UserRepository userRepository;
    private final PaymentRepository paymentRepository;
    private final MeetingRoomRepository meetingRoomRepository;
    private final BookingService bookingService; // Use @Lazy to avoid circular dependency if BookingService also calls CancellationService
    private final PaymentService paymentService; // For refund processing

    @Autowired
    public CancellationServiceImpl(CancellationRepository cancellationRepository,
                                   BookingRepository bookingRepository,
                                   UserRepository userRepository,
                                   PaymentRepository paymentRepository,
                                   MeetingRoomRepository meetingRoomRepository,
                                   @Lazy BookingService bookingService,
                                   @Lazy PaymentService paymentService) {
        this.cancellationRepository = cancellationRepository;
        this.bookingRepository = bookingRepository;
        this.meetingRoomRepository = meetingRoomRepository;
        this.userRepository = userRepository;
        this.paymentRepository = paymentRepository;
        this.bookingService = bookingService;
        this.paymentService = paymentService;
    }

    @Override
    @Transactional
    public CancellationDto requestCancellation(CancellationRequestDto requestDto, Integer customerId) {
        // 验证客户
        User customer = userRepository.findById(customerId)
                .orElseThrow(() -> new EntityNotFoundException("找不到客户ID: " + customerId));
        if (customer.getRole() != UserRole.customer) {
            throw new SecurityException("用户不是客户角色");
        }

        // 验证预订
        Booking booking = bookingRepository.findById(requestDto.getBookingId())
                .orElseThrow(() -> new EntityNotFoundException("找不到预订ID: " + requestDto.getBookingId()));

        if (!booking.getCustomer().getUserId().equals(customerId)) {
            throw new SecurityException("该预订不属于此客户");
        }

        // 检查预订状态
        if (!canBeCancelled(booking)) {
            throw new IllegalStateException("预订取消失败。无法在会议开始前24小时内取消或订单状态非已支付");
        }

        // 计算退款金额和取消费用
        CancellationDto calculation = calculateRefundAndFee(requestDto.getBookingId());

        // 创建取消申请
        Cancellation cancellation = new Cancellation();
        cancellation.setBooking(booking);
        cancellation.setCustomer(customer);
        cancellation.setRequestedAt(LocalDateTime.now());
        cancellation.setReason(requestDto.getReason());
        cancellation.setRefundRuleApplied(calculation.getRefundRuleApplied());
        cancellation.setRefundPercentage(calculation.getRefundPercentage());
        cancellation.setRefundAmount(calculation.getRefundAmount());
        cancellation.setCancellationFee(calculation.getCancellationFee());
        cancellation.setStatus(CancellationStatus.pending_review);

        Cancellation savedCancellation = cancellationRepository.save(cancellation);

        // 更新预订状态
        booking.setStatus(BookingStatus.pending_cancellation);
        bookingRepository.save(booking);

        return convertToDto(savedCancellation);
    }

    @Override
    @Transactional
    public CancellationDto systemCancellation(Booking booking, String reason) {
        if (booking == null) {
            throw new IllegalArgumentException("预订不能为空");
        }

        // 创建取消记录
        Cancellation cancellation = new Cancellation();
        cancellation.setBooking(booking);
        cancellation.setCustomer(booking.getCustomer());
        cancellation.setRequestedAt(LocalDateTime.now());
        cancellation.setReason(reason);
        cancellation.setStatus(CancellationStatus.approved);
        cancellation.setRefundAmount(booking.getTotalPrice());
        cancellation.setCancellationFee(BigDecimal.ZERO);
        cancellation.setReviewedAt(LocalDateTime.now());

        Cancellation savedCancellation = cancellationRepository.save(cancellation);

        // 更新预订状态
        booking.setStatus(BookingStatus.cancelled_payment_timeout);
        bookingRepository.save(booking);

        return convertToDto(savedCancellation);
    }

    //TODO:待深度测试
    @Override
    @Transactional
    public CancellationDto reviewCancellation(Integer cancellationId, Integer reviewerId, boolean approved, String rejectionReason) {
        // 验证审核人
        User reviewer = userRepository.findById(reviewerId)
                .orElseThrow(() -> new EntityNotFoundException("找不到审核人ID: " + reviewerId));
        if (reviewer.getRole() != UserRole.employee && reviewer.getRole() != UserRole.admin) {
            throw new SecurityException("用户没有审核权限");
        }

        // 获取取消申请
        Cancellation cancellation = cancellationRepository.findById(cancellationId)
                .orElseThrow(() -> new EntityNotFoundException("找不到取消申请ID: " + cancellationId));

        if (cancellation.getStatus() != CancellationStatus.pending_review) {
            throw new IllegalStateException("该取消申请已经被处理");
        }

        // 更新取消申请
        cancellation.setReviewer(reviewer);
        cancellation.setReviewedAt(LocalDateTime.now());
        if (approved) {
            //同时查询其它活跃订单，更新会议室对应状态。
            Booking booking = cancellation.getBooking();
            MeetingRoom room = booking.getRoom();
            // 查询该会议室的活跃订单（排除当前订单）
            List<BookingStatus> activeStatuses = Arrays.asList(
                    BookingStatus.pending_payment,
                    BookingStatus.confirmed,
                    BookingStatus.in_progress
            );
            //查询具体活跃订单，改变会议室对应状态
            List<Booking> activeBookings = bookingRepository.findByRoomRoomIdAndStatusInAndBookingIdNotAndNotExpired(
                    room.getRoomId(),
                    activeStatuses,
                    booking.getBookingId() // 排除当前订单（当前订单ID）
            );
            // 审核通过，直接处理退款
            cancellation.setStatus(CancellationStatus.refunded);
            cancellation.setRefundTransactionId("REFUND_" + System.currentTimeMillis()); // 生成模拟退款交易ID
            cancellation.setRefundedAt(LocalDateTime.now());

            // 更新支付状态为已退款
            Payment payment = paymentRepository.findByBooking(booking)
                    .orElseThrow(() -> new EntityNotFoundException("找不到预订对应的支付记录"));
            payment.setStatus(PaymentStatus.refunded);
            paymentRepository.save(payment);

            // 更新预订状态
            booking.setStatus(BookingStatus.cancelled_by_customer);
            bookingRepository.save(booking);

            // 注释：会议室状态现在只通过计算得出，不再直接设置
            // RoomStatus newStatus = determineRoomStatus(activeBookings);
            // if (room.getStatus() != RoomStatus.maintenance) {
            //     room.setStatus(newStatus);
            //     meetingRoomRepository.save(room);
            // }

            System.out.println("员工审核通过并自动退款完成 - 取消申请ID: " + cancellationId +
                    ", 审核人: " + reviewer.getFullName() +
                    ", 退款金额: " + cancellation.getRefundAmount());
        } else {
            // 审核拒绝
            cancellation.setStatus(CancellationStatus.rejected);
            cancellation.setRejectionReason(rejectionReason);

            // 恢复预订状态
            Booking booking = cancellation.getBooking();
            booking.setStatus(BookingStatus.confirmed);
            bookingRepository.save(booking);
        }

        Cancellation savedCancellation = cancellationRepository.save(cancellation);
        return convertToDto(savedCancellation);
    }

    //查询订单状态，改变对应会议室状态。
    private RoomStatus determineRoomStatus(List<Booking> activeBookings) {
        // 优先级：pending_payment > in_progress > confirmed
        if (activeBookings.stream().anyMatch(b -> b.getStatus() == BookingStatus.pending_payment)) {
            return RoomStatus.locked;
        } else if (activeBookings.stream().anyMatch(b -> b.getStatus() == BookingStatus.in_progress)) {
            return RoomStatus.in_use;
        } else if (activeBookings.stream().anyMatch(b -> b.getStatus() == BookingStatus.confirmed)) {
            return RoomStatus.booked;
        } else {
            return RoomStatus.available;
        }
    }

    @Override
    @Transactional
    public CancellationDto processRefund(Integer cancellationId, String refundTransactionId, BigDecimal actualRefundAmount) {
        Cancellation cancellation = cancellationRepository.findById(cancellationId)
                .orElseThrow(() -> new EntityNotFoundException("找不到取消申请ID: " + cancellationId));

        if (cancellation.getStatus() != CancellationStatus.approved) {
            throw new IllegalStateException("只能处理已批准的取消申请的退款");
        }

        // 处理退款
        cancellation.setRefundTransactionId(refundTransactionId);
        cancellation.setRefundAmount(actualRefundAmount);
        cancellation.setRefundedAt(LocalDateTime.now());
        cancellation.setStatus(CancellationStatus.refunded);

        return convertToDto(cancellationRepository.save(cancellation));
    }

    @Override
    public CancellationDto getCancellationDetails(Integer cancellationId) {
        return convertToDto(cancellationRepository.findById(cancellationId)
                .orElseThrow(() -> new EntityNotFoundException("找不到取消申请ID: " + cancellationId)));
    }

    @Override
    public CancellationDto getCancellationDetailsByBookingId(Integer bookingId) {
        return convertToDto(cancellationRepository.findByBookingBookingId(bookingId)
                .orElseThrow(() -> new EntityNotFoundException("找不到预订ID对应的取消申请: " + bookingId)));
    }

    @Override
    public Page<CancellationDto> getPendingReviews(Pageable pageable) {
        return cancellationRepository.findByStatus(CancellationStatus.pending_review, pageable)
                .map(this::convertToDto);
    }

    @Override
    public Page<CancellationDto> getCustomerCancellations(Integer customerId, Pageable pageable) {
        return cancellationRepository.findByCustomer_UserId(customerId, pageable)
                .map(this::convertToDto);
    }

    @Override
    public Page<CancellationDto> getCancellationsByStatus(String status, Pageable pageable) {
        try {
            CancellationStatus cancellationStatus = CancellationStatus.valueOf(status);
            return cancellationRepository.findByStatus(cancellationStatus, pageable)
                    .map(this::convertToDto);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(String.format(ErrorMessages.INVALID_CANCELLATION_STATUS, status));
        }
    }

    @Override
    public CancellationDto calculateRefundAndFee(Integer bookingId) {
        Booking booking = bookingRepository.findById(bookingId)
                .orElseThrow(() -> new EntityNotFoundException("找不到预订ID: " + bookingId));

        // 计算距离开始时间的小时数
        long hoursBeforeStart = Duration.between(LocalDateTime.now(), booking.getStartDatetime()).toHours();

        CancellationDto dto = new CancellationDto();
        dto.setBookingId(bookingId);

        // 根据提前取消时间确定退款规则
        BigDecimal refundPercentage;
        String refundRule;
        BigDecimal totalPrice = booking.getTotalPrice();

        if (hoursBeforeStart >= 72) {
            refundPercentage = new BigDecimal("1.00"); // 100%
            refundRule = "提前72小时以上取消，全额退款";
        } else if (hoursBeforeStart >= 48) {
            refundPercentage = new BigDecimal("0.75"); // 75%
            refundRule = "提前48-72小时取消，退款75%";
        } else if (hoursBeforeStart >= 24) {
            refundPercentage = new BigDecimal("0.25"); // 25%
            refundRule = "提前24-48小时取消，退款25%";
        } else {
            refundPercentage = BigDecimal.ZERO;
            refundRule = "提前不足24小时取消，不予退款";
        }

        // 计算退款金额和取消费用
        BigDecimal refundAmount = totalPrice.multiply(refundPercentage);
        BigDecimal cancellationFee = totalPrice.subtract(refundAmount);

        // 设置DTO值
        dto.setRefundRuleApplied(refundRule);
        dto.setRefundPercentage(refundPercentage);
        dto.setRefundAmount(refundAmount);
        dto.setCancellationFee(cancellationFee);

        return dto;
    }

    @Override
    @Transactional
    public CancellationDto confirmCancellation(Integer cancellationId, Integer customerId) {
        // 验证客户
        User customer = userRepository.findById(customerId)
                .orElseThrow(() -> new EntityNotFoundException("找不到客户ID: " + customerId));
        if (customer.getRole() != UserRole.customer) {
            throw new SecurityException("用户不是客户角色");
        }

        // 获取取消申请
        Cancellation cancellation = cancellationRepository.findById(cancellationId)
                .orElseThrow(() -> new EntityNotFoundException("找不到取消申请ID: " + cancellationId));

        // 验证是否是该客户的取消申请
        if (!cancellation.getCustomer().getUserId().equals(customerId)) {
            throw new SecurityException("该取消申请不属于此客户");
        }

        // 验证取消申请状态（现在直接从审核通过变为已退款）
        if (cancellation.getStatus() != CancellationStatus.refunded) {
            throw new IllegalStateException("只能确认已退款的取消申请");
        }

        // 更新客户确认状态
        cancellation.setCustomerConfirmation(CustomerConfirmationStatus.confirmed);
        cancellation.setConfirmedAt(LocalDateTime.now());

        return convertToDto(cancellationRepository.save(cancellation));
    }

    @Override
    public Page<CancellationDto> getPendingCustomerConfirmations(Integer customerId, Pageable pageable) {
        // 验证客户
        User customer = userRepository.findById(customerId)
                .orElseThrow(() -> new EntityNotFoundException("找不到客户ID: " + customerId));
        if (customer.getRole() != UserRole.customer) {
            throw new SecurityException("用户不是客户角色");
        }
        //被员工refunded的取消申请
        // 获取该客户所有待确认的取消申请
        Page<Cancellation> cancellations = cancellationRepository.findByCustomer_UserIdAndCustomerConfirmationAndStatus(
                customerId, CustomerConfirmationStatus.pending, CancellationStatus.refunded, pageable);
        return cancellations.map(this::convertToDto);
    }

    @Override
    public Page<CancellationDto> getAllPendingCustomerConfirmations(Pageable pageable) {
        // 获取所有待客户确认的取消申请
        Page<Cancellation> cancellations = cancellationRepository.findByCustomerConfirmation(
                CustomerConfirmationStatus.pending, pageable);
        return cancellations.map(this::convertToDto);
    }

    @Override
    @Transactional
    public CancellationDto resubmitCancellation(Integer customerId, Integer cancellationId, String newReason) {
        // 验证客户
        User customer = userRepository.findById(customerId)
                .orElseThrow(() -> new EntityNotFoundException("找不到客户ID: " + customerId));
        if (customer.getRole() != UserRole.customer) {
            throw new SecurityException("用户不是客户角色");
        }

        // 获取取消申请
        Cancellation cancellation = cancellationRepository.findById(cancellationId)
                .orElseThrow(() -> new EntityNotFoundException("找不到取消申请ID: " + cancellationId));

        // 验证是否是该客户的取消申请
        if (!cancellation.getCustomer().getUserId().equals(customerId)) {
            throw new SecurityException("该取消申请不属于此客户");
        }

        // 验证状态：必须是已拒绝（rejected）才能重新提交
        if (cancellation.getStatus() != CancellationStatus.rejected) {
            throw new IllegalStateException("取消申请状态不是已拒绝，无法重新提交");
        }

        // 更新取消原因和状态
        cancellation.setReason(newReason);
        cancellation.setStatus(CancellationStatus.pending_review);
        cancellation.setUpdatedAt(LocalDateTime.now());

        // 更新关联的预订状态
        Booking booking = cancellation.getBooking();
        booking.setStatus(BookingStatus.pending_cancellation);

        // 保存更新
        Cancellation updatedCancellation = cancellationRepository.save(cancellation);
        bookingRepository.save(booking);

        return convertToDto(updatedCancellation);
    }

    @Override
    public Page<CancellationDto> getCancelByStatus(Integer customerId, CancellationStatus status, Pageable pageable) {
        // 验证客户
        User customer = userRepository.findById(customerId)
                .orElseThrow(() -> new EntityNotFoundException("找不到客户ID: " + customerId));
        if (customer.getRole() != UserRole.customer) {
            throw new SecurityException("用户不是客户角色");
        }
        Page<Cancellation> cancellations = cancellationRepository.findByCustomer_UserIdAndCustomerConfirmationAndStatus(
                customerId, CustomerConfirmationStatus.pending, status, pageable);
        return cancellations.map(this::convertToDto);
    }

    private boolean canBeCancelled(Booking booking) {
        return booking.getStatus() == BookingStatus.confirmed &&
                Duration.between(LocalDateTime.now(), booking.getStartDatetime()).toHours() >= 24;
    }

    private CancellationDto convertToDto(Cancellation cancellation) {
        if (cancellation == null) {
            return null;
        }

        CancellationDto dto = new CancellationDto();
        dto.setCancellationId(cancellation.getCancellationId());
        dto.setBookingId(cancellation.getBooking().getBookingId());
        //加入会议室名称、id
        dto.setRoomId(cancellation.getBooking().getRoom().getRoomId());
        dto.setRoomName(cancellation.getBooking().getRoom().getName());
        dto.setCustomerId(cancellation.getCustomer().getUserId());
        dto.setCustomerName(cancellation.getCustomer().getUsername());
        dto.setRequestedAt(cancellation.getRequestedAt());
        dto.setReason(cancellation.getReason());
        dto.setRefundRuleApplied(cancellation.getRefundRuleApplied());
        dto.setRefundPercentage(cancellation.getRefundPercentage());
        dto.setRefundAmount(cancellation.getRefundAmount());
        dto.setCancellationFee(cancellation.getCancellationFee());
        dto.setStatus(cancellation.getStatus());

        if (cancellation.getReviewer() != null) {
            dto.setReviewerId(cancellation.getReviewer().getUserId());
            dto.setReviewerName(cancellation.getReviewer().getFullName());
        }

        dto.setReviewedAt(cancellation.getReviewedAt());
        dto.setRejectionReason(cancellation.getRejectionReason());
        dto.setRefundTransactionId(cancellation.getRefundTransactionId());
        dto.setRefundedAt(cancellation.getRefundedAt());
        dto.setCustomerConfirmation(cancellation.getCustomerConfirmation());
        dto.setConfirmedAt(cancellation.getConfirmedAt());
        dto.setCreatedAt(cancellation.getCreatedAt());
        dto.setUpdatedAt(cancellation.getUpdatedAt());

        return dto;
    }
}